import java.awt.*;
import java.awt.event.*;
import java.awt.font.TextLayout;
import java.awt.font.FontRenderContext;
import org.jdesktop.swingx.JXPanel;
import java.awt.image.*;
import javax.swing.*;
import java.util.ArrayList;
import java.io.*;
import javax.imageio.ImageIO;
import java.awt.geom.*;
import java.awt.geom.AffineTransform;
import java.net.*;
import java.util.HashSet;
import org.jdesktop.animation.timing.*;
import netscape.javascript.JSObject;


public class AlbumApplet extends JApplet {
    private CDShelf shelf;
    private JSObject js;
    private JSObject win;
    private JSlider slider;
    private AvatarPanel avatarPanel;

    private MouseAvatarSelector mouseAvatarSelector;
    private KeyAvatarSelector keyAvatarSelector;
    private CursorChanger cursorChanger;
    private MouseWheelScroller wheelScroller;
    private KeyScroller keyScroller;
    private FocusGrabber focusGrabber;
    private AvatarScroller avatarScroller;
    private AvatarEscaper avatarEscaper;
    
    private Timer scrollerTimer = null;
    private boolean filterWatcher;
    
    @Override
    public void init() {
        slider = new JSlider();
        shelf = new CDShelf();
        shelf.setParent(this);
        buildContentPane();
        //setDefaultCloseOperation(EXIT_ON_CLOSE);
        win= JSObject.getWindow(this);
        // win.eval("document.createElement('hbox')");
          
        initInputListeners();
        addInputListeners();
        
        
        
    }
    
     private void addInputListeners() {
        addMouseListener(focusGrabber);
        addMouseListener(avatarScroller);
        addMouseListener(mouseAvatarSelector);
        addMouseMotionListener(cursorChanger);
        addMouseWheelListener(wheelScroller);
        addKeyListener(keyScroller);
        addKeyListener(keyAvatarSelector);
    }
    
    private void initInputListeners() {
        // input listeners are all stateless
        // hence they can be instantiated once
        focusGrabber = new FocusGrabber();
        avatarScroller = new AvatarScroller();
        mouseAvatarSelector = new MouseAvatarSelector();
        cursorChanger = new CursorChanger();
        wheelScroller = new MouseWheelScroller();
        keyScroller = new KeyScroller();
        keyAvatarSelector = new KeyAvatarSelector();
        avatarEscaper = new AvatarEscaper();
    }
    
    private void buildContentPane() {
        getContentPane().setLayout(new StackLayout());
        add(new GradientPanel(), StackLayout.BOTTOM);
        
        
        JPanel overlay = new JPanel(new BorderLayout());
        JPanel sliderPanel = 	new JPanel(new BorderLayout());
        
        
        slider.setOrientation(javax.swing.JSlider.HORIZONTAL);
        overlay.setOpaque(false);
        
        slider.setMaximumSize(new java.awt.Dimension(50, 27));
        slider.setMinimumSize(new java.awt.Dimension(50,27));
        
        slider.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
        
        slider.setOpaque(false);
        slider.setUI(new AlbumSliderUI());
       
        slider.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderStateChanged(evt);
            }
        });
        
        
        
        
        //I think this might've killed a kitten... (BAD Code)
        sliderPanel.setOpaque(false);
        sliderPanel.add(slider,BorderLayout.CENTER);
        sliderPanel.add(Box.createRigidArea(new Dimension(0,5)),BorderLayout.SOUTH);
        overlay.add(sliderPanel, BorderLayout.SOUTH);
        
        
        add(shelf);
        add(overlay);

        
        
        
    }
    
    public void changeFilter(HashSet<String> filtered)
    {
        if(filterWatcher)
        {
            shelf.setFilter(filtered);
            System.out.println("Filter changed");
        }
        else
            filterWatcher = true;
    }
    public void setSliderValue(int n) {
       
        if (slider != null)
            slider.setValue(n);
    }
    private void sliderStateChanged(javax.swing.event.ChangeEvent evt) {
        
        if (shelf != null) {
            animateTo(slider.getValue());
            
        }
    }
    public void setAlbumCount(int count) {
        
        shelf.setAlbumCount(count);
        slider.setMinimum(0);
        slider.setMaximum(count-1);
    }
    
    public void setCurrentAlbum(String album) {
        Object[] objectArray = new Object[1];
        objectArray[0]=album;
        //js.call("alert",null);
        win.call("setAlbumFilter",objectArray);
    }
    
    public void playAlbum(String album){
        Object[] objectArray = new Object[1];
        objectArray[0]=album;
        //js.call("alert",null);
        win.call("playAlbum",objectArray);
    }
    public void setSelectedAlbum(String album, String artist) {
        shelf.setSelectedAlbum(album,artist);
    }
    
    public void setWriteMP3Tag(boolean writeMp3Tag){
        shelf.setWriteMp3Tag(writeMp3Tag);
    }
    
    public void setDownloadImage(boolean downloadImage) {
        
        shelf.setDownloadImage(downloadImage);
    }
    
    public String getCurrentAlbum() {
        return shelf.getCurrentAlbum();
    }
    
        /*
         * Adds an image to the list of images
         */
    public void addImage(String imageURI,String artist,String album) {
        
        shelf.addImage(imageURI,artist,album);
        
    }
    public void loadingDone() {
        shelf.loadingDone();
    }
    
    public void resetImages() {
        
    }
    
    public void animateTo(int n){
        
        
        if (shelf.doneLoading() && (scrollerTimer == null || !scrollerTimer.isRunning()) && n != shelf.getAvatarIndex() ) {
            
            scrollerTimer = new Timer(33, shelf.getSliderScroller(n));
            scrollerTimer.start();
        }
    }
    
    void removeAvatarFrame(){
         avatarPanel.fadeOut();
                   remove(avatarPanel);
                   
                   removeKeyListener(avatarEscaper);
                   addInputListeners();
                   paintAll(getGraphics());
    }
   private void removeInputListeners() {
        removeMouseListener(focusGrabber);
        removeMouseListener(avatarScroller);
        removeMouseListener(mouseAvatarSelector);
        removeMouseMotionListener(cursorChanger);
        removeMouseWheelListener(wheelScroller);
        removeKeyListener(keyScroller);
        removeKeyListener(keyAvatarSelector);
    }
   
   private void addAvatarListener() {
       addKeyListener(avatarEscaper);
   }
    private class MouseWheelScroller implements MouseWheelListener {
        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            int increment = e.getWheelRotation();
            scrollAndAnimateBy(increment);
            setSliderValue(shelf.getAvatarIndex());
        }
    }
    
    private class KeyScroller extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();
            switch (keyCode) {
                case KeyEvent.VK_LEFT:
                case KeyEvent.VK_UP:
                    scrollAndAnimateBy(-1);
                    setSliderValue(shelf.getAvatarIndex());
                    break;
                case KeyEvent.VK_RIGHT:
                case KeyEvent.VK_DOWN:
                    scrollAndAnimateBy(1);
                   setSliderValue(shelf.getAvatarIndex());
                    break;
                case KeyEvent.VK_END:
                    scrollBy(shelf.getCount() - shelf.getAvatarIndex() - 1);
                   setSliderValue(shelf.getAvatarIndex());
                    break;
                case KeyEvent.VK_HOME:
                    scrollBy(-shelf.getAvatarIndex() - 1);
                   setSliderValue(shelf.getAvatarIndex());
                    break;
                case KeyEvent.VK_PAGE_UP:
                    scrollAndAnimateBy(-shelf.getAmount()/ 2);
                   setSliderValue(shelf.getAvatarIndex());
                    break;
                case KeyEvent.VK_PAGE_DOWN:
                   scrollAndAnimateBy(shelf.getAmount() / 2);
                 setSliderValue(shelf.getAvatarIndex());
                    break;
            }
        }
    }
    
     private class CursorChanger extends MouseMotionAdapter {
        @Override
        public void mouseMoved(MouseEvent e) {
           
            if ((scrollerTimer != null && scrollerTimer.isRunning()) ||
                !shelf.drawableAvatarsNotNull()) {
                return;
            }
           
            CDShelf.DrawableAvatar avatar = shelf.getHitAvatar(e.getX(), e.getY());
            if (avatar != null) {
                getParent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
            } else {
                getParent().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }
    
      private void scrollAndAnimate(CDShelf.DrawableAvatar avatar) {
        if(shelf.doneLoading()) {
            scrollerTimer = new Timer(33, shelf.getAutoScroller(avatar));
            scrollerTimer.start();
        }
    }
      
    public void scrollAndAnimateBy(int increment) {
        if (shelf.doneLoading() && (scrollerTimer == null || !scrollerTimer.isRunning())) {
            
            int index = shelf.getAvatarIndex() + increment;
            if (index < 0) {
                index = 0;
            } else if (index >= shelf.getCount()) {
                index = shelf.getCount() - 1;
            }
            
            CDShelf.DrawableAvatar drawable = shelf.getDrawableAvatarByIndex(index);
           
            
            if (drawable != null) {
                scrollAndAnimate(drawable);
            } else
                scrollBy(increment);
        }
    }
    
    private void scrollBy(int increment) {
        if (shelf.doneLoading()) {
            
            if (shelf.getAvatarIndex() + increment < 0) {
                shelf.setAvatarIndex(0);
            } else if (shelf.getAvatarIndex() + increment >= shelf.getCount()) {
                shelf.setAvatarIndex(shelf.getCount() - 1);
            } else {
                shelf.setAvatarIndex(shelf.getAvatarIndex() + increment);
            }
           shelf.damaged();
            shelf.repaint();

        }
    }
    
    private class KeyAvatarSelector extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
            
            if ((scrollerTimer == null || !scrollerTimer.isRunning()) 
                    && shelf.drawableAvatarsNotNull() 
                    ) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    setCurrentAlbum(shelf.getCurrentAvatar().album);
                    playAlbum(shelf.getCurrentAvatar().album);
                }
            }
        }
    }
    
    private class MouseAvatarSelector extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent e) {
            if ((scrollerTimer == null || !scrollerTimer.isRunning()) 
                && shelf.drawableAvatarsNotNull()
                ) {
                if (e.getButton() == MouseEvent.BUTTON1) {
                    CDShelf.DrawableAvatar avatar = shelf.getHitAvatar(e.getX(), e.getY());
                   
                    if (avatar != null && avatar.getIndex() == shelf.getAvatarIndex()) {
                       if (e.getClickCount()==2)
                            playAlbum(shelf.getCurrentAvatar().album);
                       else
                           setCurrentAlbum(shelf.getCurrentAvatar().album);
                       
                    }
                } 
                else if (e.getButton() == MouseEvent.BUTTON3) {
                    CDShelf.DrawableAvatar avatar = shelf.getHitAvatar(e.getX(), e.getY());
                    if (avatar != null && avatar.getIndex() == shelf.getAvatarIndex()) {
                        avatarPanel = new AvatarPanel(shelf.getCurrentAvatar(),AlbumApplet.this);
                       
                       add(avatarPanel,StackLayout.TOP);
                       avatarPanel.fadeIn();
                       paintAll(getGraphics());
                       addAvatarListener();
                        removeInputListeners();
                       System.out.println(shelf.getCurrentAlbum());
                    }
                   
                }
            }
        }
    }
    
     private class FocusGrabber extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent e) {
            requestFocus();
        }
    }
    
    private class AvatarScroller extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent e) {
            if ((scrollerTimer != null && scrollerTimer.isRunning()) 
                    || !shelf.drawableAvatarsNotNull()
                    ) {
                return;
            }
            
            if (e.getButton() == MouseEvent.BUTTON1) {
                CDShelf.DrawableAvatar avatar = shelf.getHitAvatar(e.getX(), e.getY());
                if (avatar != null && avatar.getIndex() != shelf.getAvatarIndex()
                ) {
                    scrollAndAnimate(avatar);
                    setSliderValue(shelf.getAvatarIndex());
                    if (e.getClickCount() == 2)
                        playAlbum(shelf.getCurrentAvatar().album);
                }
            }
            if (e.getButton() == MouseEvent.BUTTON3) {
                CDShelf.DrawableAvatar avatar = shelf.getHitAvatar(e.getX(), e.getY());
                if (avatar != null && avatar.getIndex() != shelf.getAvatarIndex()
                ) {
                    scrollAndAnimate(avatar);
                    setSliderValue(shelf.getAvatarIndex());
                }
            }
        }
    }
    
    private class AvatarEscaper extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
                
               if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                  removeAvatarFrame();
                }
            }
        }
    
    }